//
//  NSDate+YYAdd.m
//  YYKit <https://github.com/ibireme/YYKit>
//
//  Created by ibireme on 13/4/11.
//  Copyright (c) 2015 ibireme.
//
//  This source code is licensed under the MIT-style license found in the
//  LICENSE file in the root directory of this source tree.
//

#import "NSDate+YYAdd.h"
#import "YYKitMacro.h"
#import <time.h>
static const unsigned componentFlags = (NSCalendarUnitYear| NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitWeekOfMonth | NSCalendarUnitWeekOfYear |  NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond | NSCalendarUnitWeekday | NSCalendarUnitWeekdayOrdinal);

YYSYNTH_DUMMY_CLASS(NSDate_YYAdd)


@implementation NSDate (YYAdd)

- (NSInteger)year {
    return [[[NSCalendar currentCalendar] components:NSCalendarUnitYear fromDate:self] year];
}

- (NSInteger)month {
    return [[[NSCalendar currentCalendar] components:NSCalendarUnitMonth fromDate:self] month];
}

- (NSInteger)day {
    return [[[NSCalendar currentCalendar] components:NSCalendarUnitDay fromDate:self] day];
}

- (NSInteger)hour {
    return [[[NSCalendar currentCalendar] components:NSCalendarUnitHour fromDate:self] hour];
}

- (NSInteger)minute {
    return [[[NSCalendar currentCalendar] components:NSCalendarUnitMinute fromDate:self] minute];
}

- (NSInteger)second {
    return [[[NSCalendar currentCalendar] components:NSCalendarUnitSecond fromDate:self] second];
}

- (NSInteger)nanosecond {
    return [[[NSCalendar currentCalendar] components:NSCalendarUnitSecond fromDate:self] nanosecond];
}

- (NSInteger)weekday {
    return [[[NSCalendar currentCalendar] components:NSCalendarUnitWeekday fromDate:self] weekday];
}

- (NSInteger)weekdayOrdinal {
    return [[[NSCalendar currentCalendar] components:NSCalendarUnitWeekdayOrdinal fromDate:self] weekdayOrdinal];
}

- (NSInteger)weekOfMonth {
    return [[[NSCalendar currentCalendar] components:NSCalendarUnitWeekOfMonth fromDate:self] weekOfMonth];
}

- (NSInteger)weekOfYear {
    return [[[NSCalendar currentCalendar] components:NSCalendarUnitWeekOfYear fromDate:self] weekOfYear];
}

- (NSInteger)yearForWeekOfYear {
    return [[[NSCalendar currentCalendar] components:NSCalendarUnitYearForWeekOfYear fromDate:self] yearForWeekOfYear];
}

- (NSInteger)quarter {
    return [[[NSCalendar currentCalendar] components:NSCalendarUnitQuarter fromDate:self] quarter];
}

- (BOOL)isLeapMonth {
    return [[[NSCalendar currentCalendar] components:NSCalendarUnitQuarter fromDate:self] isLeapMonth];
}

- (BOOL)isLeapYear {
    NSUInteger year = self.year;
    return ((year % 400 == 0) || ((year % 100 != 0) && (year % 4 == 0)));
}

- (BOOL)isToday {
    if (fabs(self.timeIntervalSinceNow) >= 60 * 60 * 24) return NO;
    return [NSDate new].day == self.day;
}

- (BOOL)isYesterday {
    NSDate *added = [self dateByAddingDays:1];
    return [added isToday];
}

- (NSDate *)dateByAddingYears:(NSInteger)years {
    NSCalendar *calendar =  [NSCalendar currentCalendar];
    NSDateComponents *components = [[NSDateComponents alloc] init];
    [components setYear:years];
    return [calendar dateByAddingComponents:components toDate:self options:0];
}

- (NSDate *)dateByAddingMonths:(NSInteger)months {
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSDateComponents *components = [[NSDateComponents alloc] init];
    [components setMonth:months];
    return [calendar dateByAddingComponents:components toDate:self options:0];
}

- (NSDate *)dateByAddingWeeks:(NSInteger)weeks {
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSDateComponents *components = [[NSDateComponents alloc] init];
    [components setWeekOfYear:weeks];
    return [calendar dateByAddingComponents:components toDate:self options:0];
}

- (NSDate *)dateByAddingDays:(NSInteger)days {
    NSTimeInterval aTimeInterval = [self timeIntervalSinceReferenceDate] + 86400 * days;
    NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval];
    return newDate;
}

- (NSDate *)dateByAddingHours:(NSInteger)hours {
    NSTimeInterval aTimeInterval = [self timeIntervalSinceReferenceDate] + 3600 * hours;
    NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval];
    return newDate;
}

- (NSDate *)dateByAddingMinutes:(NSInteger)minutes {
    NSTimeInterval aTimeInterval = [self timeIntervalSinceReferenceDate] + 60 * minutes;
    NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval];
    return newDate;
}

- (NSDate *)dateByAddingSeconds:(NSInteger)seconds {
    NSTimeInterval aTimeInterval = [self timeIntervalSinceReferenceDate] + seconds;
    NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval];
    return newDate;
}

- (NSString *)stringWithFormat:(NSString *)format {
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:format];
    [formatter setLocale:[NSLocale currentLocale]];
    return [formatter stringFromDate:self];
}

- (NSString *)stringWithFormat:(NSString *)format timeZone:(NSTimeZone *)timeZone locale:(NSLocale *)locale {
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:format];
    if (timeZone) [formatter setTimeZone:timeZone];
    if (locale) [formatter setLocale:locale];
    return [formatter stringFromDate:self];
}

- (NSString *)stringWithISOFormat {
    static NSDateFormatter *formatter = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        formatter = [[NSDateFormatter alloc] init];
        formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
        formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZ";
    });
    return [formatter stringFromDate:self];
}

+ (NSDate *)dateWithString:(NSString *)dateString format:(NSString *)format {
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:format];
    return [formatter dateFromString:dateString];
}

+ (NSDate *)dateWithString:(NSString *)dateString format:(NSString *)format timeZone:(NSTimeZone *)timeZone locale:(NSLocale *)locale {
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:format];
    if (timeZone) [formatter setTimeZone:timeZone];
    if (locale) [formatter setLocale:locale];
    return [formatter dateFromString:dateString];
}

+ (NSDate *)dateWithISOFormatString:(NSString *)dateString {
    static NSDateFormatter *formatter = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        formatter = [[NSDateFormatter alloc] init];
        formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
        formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZ";
    });
    return [formatter dateFromString:dateString];
}

- (NSString*)stringValueWithFormatString:(NSString*)formatString
{
    return [self stringDateByFormatString:formatString withDate:self];
}

//根据指定时间的字符串格式和时间 格式例如yyyy-MM-dd HH:mm:ss:SSS
- (NSString*)stringDateByFormatString:(NSString*)formatString withDate:(NSDate*)date
{
    static NSDateFormatter* dateFromatter = nil;
    NSString* strDate = nil;
    if (!dateFromatter) {
        dateFromatter = [[NSDateFormatter alloc] init];
        [dateFromatter setTimeStyle:NSDateFormatterShortStyle];
    }
    
    if (date == nil) {
        return @"";
    }
    
    @synchronized(dateFromatter)
    {
        //        [dateFromatter setTimeZone:[NSTimeZone timeZoneWithName:@"UTC"]];
        if (formatString != nil) {
            [dateFromatter setDateFormat:formatString];
        }
        strDate = [dateFromatter stringFromDate:date];
    }
    
    return strDate;
}


/**
 *  日期是不是明天
 *
 *  @return YES  是 NO 不是
 */
- (BOOL) isTomorrow {
    return [self isEqualToDateIgnoringTime:[NSDate dateTomorrow]];
}
/**
 *  抛弃时间外 日期是否相等 精确到天的范围内
 *
 *  @param aDate 比较的date
 *
 *  @return YES 相等 NO 不相等
 */
- (BOOL) isEqualToDateIgnoringTime: (NSDate *) aDate {
    NSDateComponents *components1 = [[NSDate currentCalendar] components:componentFlags fromDate:self];
    NSDateComponents *components2 = [[NSDate currentCalendar] components:componentFlags fromDate:aDate];
    return ((components1.year == components2.year) &&
            (components1.month == components2.month) &&
            (components1.day == components2.day));
}

/**
 *  获获取当前客户端的逻辑日历
 *
 *  @return 当前客户端的逻辑日历
 */
+ (NSCalendar *) currentCalendar {
    static NSCalendar *sharedCalendar = nil;
    if (!sharedCalendar) {
        sharedCalendar = [NSCalendar autoupdatingCurrentCalendar];
    }
    return sharedCalendar;
}

/**
 *  明天的日期
 *
 *  @return 明天的日期
 */
+ (NSDate *) dateTomorrow {
    return [self convertDateToLocalTime:[NSDate dateWithDaysFromNow:1]];
}

/**
 *  昨天的日期
 *
 *  @return 昨天日期
 */
+ (NSDate *) dateYesterday {
    return [self convertDateToLocalTime:[NSDate dateWithDaysBeforeNow:1]];
}
/**
 *  现在的日期
 *
 *  @return 现在的日期
 */
+ (NSDate *) dateNow {
    return [self convertDateToLocalTime:[NSDate date]];
}

/**
 *  将日期转换为当前时区的日期
 *
 *  @param forDate 要转换的日期
 *
 *  @return 转换过的日期
 */
+ (NSDate *)convertDateToLocalTime: (NSDate *)forDate {
    
    NSTimeZone *nowTimeZone = [NSTimeZone localTimeZone];
    NSInteger timeOffset = [nowTimeZone secondsFromGMTForDate:forDate];
    NSDate *newDate = [forDate dateByAddingTimeInterval:timeOffset];
    return newDate;
}

/**
 *  从现在起向后推几天的日期
 *
 *  @param days 向后推的天数
 *
 *  @return 后推得到的日期
 */
+ (NSDate *) dateWithDaysFromNow: (NSInteger) days {
    return [self convertDateToLocalTime:[[NSDate date] dateByAddingDays:days]];
}

/**
 *  从现在起向前推几天的日期
 *
 *  @param days 向前推的天数
 *
 *  @return 前推得到的日期
 */
+ (NSDate *) dateWithDaysBeforeNow: (NSInteger) days {
    return [self convertDateToLocalTime:[[NSDate date] dateByAddingDays:days]];
    
    return [[NSDate date] dateBySubtractingDays:days];
}

/**
 *  指定日期前推几天的到的日期
 *
 *  @param dDays 前推的天数
 *
 *  @return 前推得到的日期
 */
- (NSDate *) dateBySubtractingDays: (NSInteger) dDays {
    return [self dateByAddingDays: (dDays * -1)];
}

/**
 *  判断一个日期是不是在将来
 *
 *  @return YES 是 NO 不是
 */
- (BOOL) isInFuture {
    return ([self isLaterThanDate:[NSDate date]]);
}

/**
 *  判断一个日期是不是在过去
 *
 *  @return YES 是 NO 不是
 */
- (BOOL) isInPast {
    return ([self isEarlierThanDate:[NSDate date]]);
}

/**
 *  判断是不是比指定日期早
 *
 *  @param aDate 指定的日期
 *
 *  @return YES 早 NO 不早
 */
- (BOOL) isEarlierThanDate: (NSDate *) aDate {
    return ([self compare:aDate] == NSOrderedAscending);
}

/**
 *  判断是不是比指定日期晚
 *
 *  @param aDate 指定的日期
 *
 *  @return YES 晚 NO 不晚
 */
- (BOOL) isLaterThanDate: (NSDate *) aDate {
    return ([self compare:aDate] == NSOrderedDescending);
}

/**
 *  获取某个日期是星期几
 *  eg: featureDate = @""2018-04-30 17:20:47""
 *
 */
+ (NSString *)getWeekdayWithDate:(NSString *)dateStr {
    
    NSInteger day = 0;
    NSInteger month = 0;
    NSInteger year = 0;
    if ([dateStr rangeOfString:@" "].location == NSNotFound) {
        NSArray *dateArr = [dateStr componentsSeparatedByString:@"-"];
        if (dateArr.count == 3) {
            year = [dateArr[0] intValue];
            month = [dateArr[1] intValue];
            day = [dateArr[2] intValue];
        }
    } else {
        NSArray *arr = [dateStr componentsSeparatedByString:@" "];
        if (arr.count == 2) {
            NSString *str = arr[0];
            NSArray *dateArr = [str componentsSeparatedByString:@"-"];
            if (dateArr.count == 3) {
                year = [dateArr[0] intValue];
                month = [dateArr[1] intValue];
                day = [dateArr[2] intValue];
            }
        }
    }
    
    NSDateComponents *comps = [[NSDateComponents alloc] init];
    [comps setDay:day];
    [comps setMonth:month];
    [comps setYear:year];
    NSCalendar *gregorian = [[NSCalendar alloc]
                             initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
    NSDate *date = [gregorian dateFromComponents:comps];
    NSDateComponents *weekdayComponents =
    [gregorian components:NSCalendarUnitWeekday fromDate:date];
    NSInteger weekday = [weekdayComponents weekday];
    
    switch (weekday) {
        case 1:
            return @"周日";
            break;
        case 2:
            return @"周一";
            break;
        case 3:
            return @"周二";
            break;
        case 4:
            return @"周三";
            break;
        case 5:
            return @"周四";
            break;
        case 6:
            return @"周五";
            break;
        case 7:
            return @"周六";
            break;
            
        default:
            break;
    }
    return nil;
    
}


/**
 时间转换：NSDate to NSString
 
 @author Sam
 @param date 对象类型时间
 @param formate 时间格式
 @return 字符串类型时间
 */
+(NSString*)stringTimeWithDate:(NSDate*)date DateFormate:(NSString*)formate{
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:formate];
    return [dateFormatter stringFromDate:date];
}

/**
 时间转换：NSString to NSDate
 
 @author Sam
 @param dateString 字符串时间
 @param formate 时间格式
 @return 对象类型时间
 */
+(NSDate*)dateTimeWithDateString:(NSString*)dateString DateFormate:(NSString*)formate{
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:formate];
    NSDate *date = [dateFormatter dateFromString:dateString];
    return [self timeZoneOfChinaWithDate:date];
}

/**
 获取当前时区的时间
 
 @author Sam
 @param date 时间值
 @return NSDate
 */
+(NSDate*)timeZoneOfChinaWithDate:(NSDate*)date{
    NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:@"Asia/Beijing"];
    NSInteger interval = [timeZone secondsFromGMTForDate:date];
    return [date  dateByAddingTimeInterval:interval];
}

/**
 获取当前时间
 
 @author Sam
 @param formate 时间格式，formate = nil 时间格式为：YYYY-MM-dd HH:mm:ss
 @return 字符串的时间
 */
+(NSString*)getCurrentTimeWithDateFormate:(NSString*)formate{
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    if (!formate || formate.length <= 0) {
        [formatter setDateFormat:@"YYYY-MM-dd HH:mm:ss"];
    }else{
        [formatter setDateFormat:formate];
    }
    NSDate *datenow = [NSDate date];
    return [formatter stringFromDate:datenow];
}

/**
 获取当前时间的时间戳
 
 @author Sam
 @param type 时间格式
 @return 字符串的时间戳
 */
+(NSString *)getCurrentTimeTimestamp:(SEGEnumTimerstamp)type{
    return [self getTimestampWithDate:[NSDate date] timestmapType:type];
}

/**
 获取指定时间的时间戳
 
 @author Sam
 @param dateString 需要转换成时间戳的时间字符串
 @param formate 需要转换成时间戳的时间字符串的时间格式
 @param type 时间格式
 @return 字符串的时间戳
 */
+(NSString *)getTimestampWithDateString:(NSString*)dateString dateFormate:(NSString*)formate timestmapType:(SEGEnumTimerstamp)type{
    NSDate *dateTime = [self dateTimeWithDateString:dateString DateFormate:formate];
    return [self getTimestampWithDate:dateTime timestmapType:type];
}

/**
 获取指定时间的时间戳
 
 @author Sam
 @param date 时间对象
 @param type 时间格式
 @return 字符串的时间戳
 */
+(NSString *)getTimestampWithDate:(NSDate*)date timestmapType:(SEGEnumTimerstamp)type{
    date = [self timeZoneOfChinaWithDate:date];
    if (type == SEGEnumTimerstamp_Second)return [NSString stringWithFormat:@"%ld", (long)[date timeIntervalSince1970]];
    return [NSString stringWithFormat:@"%ld", (long)[date timeIntervalSince1970]*1000];;
}

/**
 时间戳转成时间字符串
 
 @author Sam
 @param timestamp 时间戳
 @param formate 转成明文时间的格式
 @param type 时间戳时间类型：秒、毫秒
 @return 字符串时间
 */
+(NSString *)getDateStringWithTimestamp:(NSString*)timestamp dateFormate:(NSString*)formate timestmapType:(SEGEnumTimerstamp)type{
    NSDateFormatter* formatter = [[NSDateFormatter alloc] init];
    formatter.timeZone = [NSTimeZone timeZoneWithName:@"Asia/Beijing"];
    [formatter setDateStyle:NSDateFormatterMediumStyle];
    [formatter setTimeStyle:NSDateFormatterShortStyle];
    if (!formate || formate.length <= 0) {
        [formatter setDateFormat:@"YYYY-MM-dd HH:mm:ss"];
    }else{
        [formatter setDateFormat:formate];
    }
    
    NSDate* date = [NSDate dateWithTimeIntervalSince1970:(type == SEGEnumTimerstamp_Second) ? [timestamp doubleValue] : ([timestamp doubleValue]/ 1000.0)];
    return [formatter stringFromDate:date];
}

- (NSString*)stringNoUTCDateByFormatString:(NSString*)formatString
{
    static NSDateFormatter* dateFromatter = nil;
    NSString* strDate = nil;
    if (!dateFromatter) {
        dateFromatter = [[NSDateFormatter alloc] init];
        [dateFromatter setTimeStyle:NSDateFormatterShortStyle];
    }
    
    if (self == nil) {
        return @"";
    }
    
    @synchronized(dateFromatter)
    {
        if (formatString != nil) {
            [dateFromatter setDateFormat:formatString];
        }
        strDate = [dateFromatter stringFromDate:self];
    }
    
    return strDate;
}

/**
 统一转换时间文本的格式

 @param dateStr 时间文本
 @return 转换之后的格式
 */
+ (NSString*)formatDateString:(NSString*)dateStr
{
    //输入时间
    NSDate* inputdate = [NSDate dateWithTimeIntervalSince1970:[dateStr doubleValue] / 1000];
    
    NSDateFormatter* inputFormatter = [[NSDateFormatter alloc] init];
    inputFormatter.timeZone = [[NSTimeZone alloc] initWithName:@"Asia/Beijing"];
    
    [inputFormatter setDateFormat:@"yyyy"];
    NSString* nowyear = [inputFormatter stringFromDate:[NSDate date]];
    NSString* inputyear = [inputFormatter stringFromDate:inputdate];
    int yearDistance = [nowyear intValue] - [inputyear intValue];
    
    [inputFormatter setDateFormat:@"MM"];
    NSString* nowmonth = [inputFormatter stringFromDate:[NSDate date]];
    NSString* inputmonth = [inputFormatter stringFromDate:inputdate];
    int monthDistance = [nowmonth intValue] - [inputmonth intValue];
    
    [inputFormatter setDateFormat:@"dd"];
    NSString* nowday = [inputFormatter stringFromDate:[NSDate date]];
    NSString* inputday = [inputFormatter stringFromDate:inputdate];
    int dayDistance = [nowday intValue] - [inputday intValue];
    
    NSString* date = nil;
    if (yearDistance == 0 && monthDistance == 0 && dayDistance == 0) {
        
        [inputFormatter setDateFormat:@"HH:mm"];
        date = [inputFormatter stringFromDate:inputdate];
    }
    else if (yearDistance == 0 && monthDistance == 0 && dayDistance == 1) {
        
        [inputFormatter setDateFormat:@"HH:mm"];
        date = [NSString stringWithFormat:@"昨天 %@", [inputFormatter stringFromDate:inputdate]];
    }
    else {
        
        [inputFormatter setDateFormat:@"yyyy-MM-dd HH:mm"];
        date = [inputFormatter stringFromDate:inputdate];
    }
    return date;
}

@end
